The present invention relates generally to computer programs, and more specifically to enhancing the execution performance of program code by separating code modules from their original module containers into new module containers.
In many computer program products, much of the computer code is used very infrequently. In many cases, specific sections of computer code are not required at all for many usage scenarios. Loading sections of computer code that are not required for the specific usage scenario under consideration can often result in inefficient allocation of computer resources. This is the case because loading computer code utilizes processing time and memory. When a section of computer code is never used, no benefit is accrued in return for the misallocated computing resources.
Most computer languages group related computer code into discrete units. This is the case in most programming paradigms, including object-oriented programming and procedural programming. For instance, Java, an object-oriented programming language, groups related computer code into units called packages, classes and methods. Each class is assigned to a package. Each method is enclosed within a class. C, a procedural programming language, groups related computer code into units called functions. Functions are placed in files on a storage medium, with files serving as larger grouping units.
It is common practice in the art for computer code to be grouped in a manner which intuitively makes sense to humans and which facilitates human understanding of the code. This is often necessary and beneficial, because it reduces the time and resources required to develop computer code and increases the quality of the code. For example, suppose a Java programmer wishes to develop computer code to control an industrial machine which produces widgets. According to common practice in the art, the Java programmer would likely create one class to encapsulate all the computer code required to control the machine. The class would include methods which control the normal operation of the industrial process. The class would also include methods which allow reconfiguring the machine to begin producing a different model of widget. This categorization system beneficially allows any person to look at a single location, the class, to find any method related to the operation of the machine.
In many computer languages, the manner in which code is grouped determines the manner in which it is loaded and possibly whether it is loaded at all. This, in turn, impacts the performance and memory usage of the computer program product. Consider, for example, the dynamic class loading technique used by the Java platform. In this technique, a class is not loaded into memory until and unless it is invoked or otherwise referenced by other computer code within the computer program product during runtime. However, once even a single method of a class is invoked, the entire class is loaded. Dynamic class loading may reduce the time to initialize a program, because only those classes used during initialization must be loaded at that time. Moreover, when not all the code is necessary for a given runtime scenario, dynamic class loading may also improve performance and/or reduce memory usage by avoiding the loading of classes for which none of the code is needed. However, if a class includes some code which is needed and other code which is not needed, the entire class, including the unnecessary code, must be loaded. Thus, infrequently-used code may always be loaded if it is part of a class for which other computer code is usually needed. Consider, for example, the class discussed above which models the industrial machine. Because the same model of widget is normally produced for extended periods of time, the methods to reconfigure the machine are invoked only rarely. But because these methods are part of the class, they are loaded into memory even for the most common case, the case in which the machine repeatedly produces the same widget.
As this example shows, division of code based on human factors frequently fails to result in the most efficient groupings from a technical standpoint. In particular, the code groupings which seem logical to humans tend to include both frequently-used code and infrequently-used code. Therefore, loading code according to categorizations defined manually by programmers frequently results in sub-optimal performance and/or unnecessary memory usage.
Other techniques exist to improve the runtime performance of a computer program product. For example, on the Java platform, techniques exist to automatically identify blocks of bytecodes which are especially critical to performance. In these techniques, blocks thus identified are compiled to native code in advance of program execution instead of being interpreted as bytecodes during runtime.
Another technique is just-in-time (JIT) compilation, which endeavors to improve the performance of interpreted languages and bytecode-based languages such as Java. In JIT compilation, profiling is used during runtime to identify methods which are called frequently. Methods thus identified are then compiled to native code.
Unfortunately, neither technique completely resolves the unnecessary loading of code. Loading computer code not utilized can degrade performance, regardless of whether or not the unnecessary code is native to the computer hardware on which it is executing. In fact, such techniques may even worsen performance in some situations. For example, analyzing and possibly compiling the unneeded code requires computing resources, yet there is no savings in runtime because the code is never executed.